package gms;

import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 * manage the DHT token ring mappings. an token is mapped to only
 * one virtual node in the ring
 * @author xiafan
 *
 */
public class TokenMetaData {
	private Map<IToken, InetAddress> DHTRing = new TreeMap<IToken, InetAddress>();
	private List<IToken> DHTRingList = null;
	/**
	 * should this function the thread safe?
	 * @return
	 */
	public List<IToken> getDHTRing() {
		if (DHTRingList == null)
			updateDHTRingList();
		return DHTRingList;
	}
	
	public void addNewNode(IToken token, InetAddress node) {
		DHTRing.put(token, node);
		updateDHTRingList();
	}
	
	public void removeNewNode(IToken token) {
		DHTRing.remove(token);
		updateDHTRingList();
	}
	
	private void updateDHTRingList() {
		DHTRingList =  new ArrayList<IToken>(DHTRing.keySet());
	}
	
	public List<InetAddress> lookupNodes(IToken token, int topK) {
		List<IToken> ring =  getDHTRing();
		int index = Collections.binarySearch(ring, token);
		if (index < 0) 
			index = Math.abs(index) - 1;
		
		List<InetAddress> ret = new ArrayList<InetAddress>();
		for (int i = 0; i < topK; i++) {
			ret.add(DHTRing.get(ring.get((index + i)%ring.size())));
		}
		return ret;
	}
}
